<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="CYxWw" id="CYxWw"><span data-lake-id="u9dfb97a8" id="u9dfb97a8">典型回答</span></h1>
  <p data-lake-id="u74bb9a34" id="u74bb9a34"><br></p>
  <p data-lake-id="ubecc040b" id="ubecc040b"><span data-lake-id="u546dfa13" id="u546dfa13">当我们在同一个线程中，想要共享变量的话，是可以直接使用ThreadLocal的，但是如果在父子线程之间，共享变量，ThreadLocal就不行了。</span></p>
  <p data-lake-id="u0e98375a" id="u0e98375a"><span data-lake-id="ued4cd324" id="ued4cd324">​</span><br></p>
  <p data-lake-id="uab2bab06" id="uab2bab06"><span data-lake-id="ue00dc336" id="ue00dc336">如以下代码，会抛出NPE：</span></p>
  <pre lang="java"><code>
public static ThreadLocal&lt;Integer&gt; sharedData = new ThreadLocal&lt;&gt;();


public static void main(String[] args) {
    sharedData.set(0);
    MyThread thread = new MyThread();
    thread.start();
    sharedData.set(sharedData.get() + 1);
    System.out.println("sharedData in main thread: " + sharedData.get());

}

static class MyThread extends Thread {

    @Override
    public void run() {
        System.out.println("sharedData in child thread: " + sharedData.get());
        sharedData.set(sharedData.get() + 1);
        System.out.println("sharedData in child thread after increment: " + sharedData.get());
    }
}
</code></pre>
  <p data-lake-id="u682807ad" id="u682807ad"><span data-lake-id="u3006ac4b" id="u3006ac4b">​</span><br></p>
  <p data-lake-id="u067f3248" id="u067f3248"><span data-lake-id="ua6b924ae" id="ua6b924ae">输出结果：</span></p>
  <p data-lake-id="u75760452" id="u75760452"><span data-lake-id="uedfb8046" id="uedfb8046">​</span><br></p>
  <pre lang="java"><code>
sharedData in child thread: null
sharedData in main thread: 1
Exception in thread "Thread-0" java.lang.NullPointerException
	at com.hollis.java.bagu$MyThread.run(JavaBaguThreadLocalTest.java:30)
</code></pre>
  <p data-lake-id="ua4737a8a" id="ua4737a8a"><span data-lake-id="u19ea6500" id="u19ea6500">​</span><br></p>
  <p data-lake-id="u0a5ca27c" id="u0a5ca27c"><span data-lake-id="u4fe81903" id="u4fe81903">因为ThreadLocal 变量是为每个线程提供了独立的副本，因此不同线程之间只能访问它们自己的副本。</span></p>
  <p data-lake-id="uc5466b5a" id="uc5466b5a"><span data-lake-id="u86f9efa8" id="u86f9efa8">​</span><br></p>
  <p data-lake-id="u3ce56092" id="u3ce56092"><span data-lake-id="uef61ad81" id="uef61ad81">那么，想要实现数据共享，主要有两个办法，第一个是自己传递，第二个是借助InheritableThreadLocal</span></p>
  <p data-lake-id="u70fc2f8a" id="u70fc2f8a"><span data-lake-id="ue634146f" id="ue634146f">​</span><br></p>
  <h4 data-lake-id="cS2QR" id="cS2QR"><span data-lake-id="ubd837248" id="ubd837248">自己传递</span></h4>
  <p data-lake-id="u98148515" id="u98148515"><br></p>
  <p data-lake-id="ufee80f97" id="ufee80f97"><span data-lake-id="u827aabfc" id="u827aabfc">我们可以在子线程中创建一个成员变量，这样在主线程创建子线程的时候，可以给成员变量赋值，这样实现数据共享。</span></p>
  <p data-lake-id="u703ae250" id="u703ae250"><span data-lake-id="ucea6dadb" id="ucea6dadb">​</span><br></p>
  <pre lang="java"><code>
import java.util.concurrent.ConcurrentHashMap;

public class SharedDataExample {
   public static void main(String[] args) {
      ConcurrentHashMap&lt;String, String&gt; sharedData = new ConcurrentHashMap&lt;String, String&gt;();
      MyThread thread = new MyThread(sharedData);
      thread.start();
      sharedData.put("key", "value");
      System.out.println("sharedData in main thread: " + sharedData.get("key"));
   }
}

class MyThread extends Thread {
   ConcurrentHashMap&lt;String, String&gt; sharedData;
   public MyThread(ConcurrentHashMap&lt;String, String&gt; data) {
      this.sharedData = data;
   }
   public void run() {
      sharedData.put("key", "new value");
      System.out.println("sharedData in child thread: " + sharedData.get("key"));
   }
}

</code></pre>
  <p data-lake-id="uc527ac70" id="uc527ac70"><span data-lake-id="u9267e9d6" id="u9267e9d6">但是一定要考虑线程安全的问题。</span></p>
  <p data-lake-id="ubdcaed6b" id="ubdcaed6b"><br></p>
  <p data-lake-id="uc3d9a82f" id="uc3d9a82f"><span data-lake-id="u373b3fd5" id="u373b3fd5">输出结果：</span></p>
  <p data-lake-id="u9a7a3828" id="u9a7a3828"><span data-lake-id="u7de18ec8" id="u7de18ec8">​</span><br></p>
  <pre lang="java"><code>
sharedData in child thread: new value
sharedData in main thread: new value
</code></pre>
  <h4 data-lake-id="Eye39" id="Eye39"><br></h4>
  <h4 data-lake-id="VhoAj" id="VhoAj"><span data-lake-id="uff0aa5de" id="uff0aa5de">InheritableThreadLocal</span></h4>
  <p data-lake-id="u23d4a931" id="u23d4a931"><br></p>
  <p data-lake-id="u8096fc47" id="u8096fc47"><span data-lake-id="ucbecbfca" id="ucbecbfca">与 ThreadLocal 不同，</span><strong><span data-lake-id="uf1bb2034" id="uf1bb2034">InheritableThreadLocal 可以在子线程中继承父线程中的值</span></strong><span data-lake-id="u2374281a" id="u2374281a">。在创建子线程时，子线程将复制父线程中的 InheritableThreadLocal 变量。</span></p>
  <p data-lake-id="u64fe9e13" id="u64fe9e13"><span data-lake-id="ud0210bc6" id="ud0210bc6">​</span><br></p>
  <p data-lake-id="u4e15230a" id="u4e15230a"><span data-lake-id="u8541f052" id="u8541f052">我们把开头的示例中ThreadLocal改成InheritableThreadLocal&#x0;就可以了：</span></p>
  <p data-lake-id="u46dbe25b" id="u46dbe25b"><span data-lake-id="uad349b49" id="uad349b49">​</span><br></p>
  <pre lang="java"><code>
    public static InheritableThreadLocal&lt;Integer&gt; sharedData = new InheritableThreadLocal&lt;&gt;();


    public static void main(String[] args) {
        sharedData.set(0);
        MyThread thread = new MyThread();
        thread.start();
        sharedData.set(sharedData.get() + 1);
        System.out.println("sharedData in main thread: " + sharedData.get());

    }

    static class MyThread extends Thread {

        @Override
        public void run() {
            System.out.println("sharedData in child thread: " + sharedData.get());
            sharedData.set(sharedData.get() + 1);
            System.out.println("sharedData in child thread after increment: " + sharedData.get());
        }
    }
</code></pre>
  <p data-lake-id="uf1b936b2" id="uf1b936b2"><span data-lake-id="ub4035592" id="ub4035592">​</span><br></p>
  <p data-lake-id="u3def2ae2" id="u3def2ae2"><span data-lake-id="u38b889b5" id="u38b889b5">输出结果：</span></p>
  <pre lang="java"><code>
sharedData in child thread: 0
sharedData in main thread: 1
sharedData in child thread after increment: 1
</code></pre>
  <p data-lake-id="u4fefb8e2" id="u4fefb8e2"><span data-lake-id="u1950e959" id="u1950e959">​</span><br></p>
  <h1 data-lake-id="Pt7fm" id="Pt7fm"><span data-lake-id="u116245b7" id="u116245b7">扩展知识</span></h1>
  <p data-lake-id="u9cfc8bf0" id="u9cfc8bf0"><br></p>
  <h2 data-lake-id="yhR9D" id="yhR9D"><span data-lake-id="u10c86692" id="u10c86692">InheritableThreadLocal的原理</span></h2>
  <p data-lake-id="uce30c684" id="uce30c684"><br></p>
  <p data-lake-id="uc71fdb37" id="uc71fdb37"><span data-lake-id="uc7958bb7" id="uc7958bb7">当我们通过Thread的构造方法创建线程的时候，会调用到java.lang.Thread#init方法，这个方法中针对InheritableThreadLocal有一些特殊的处理：</span></p>
  <p data-lake-id="uce9a074a" id="uce9a074a"><span data-lake-id="u68c52d03" id="u68c52d03">​</span><br></p>
  <pre lang="java"><code>
if (inheritThreadLocals &amp;&amp; parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
</code></pre>
  <p data-lake-id="ue1fd7c97" id="ue1fd7c97"><br></p>
  <p data-lake-id="u7b279539" id="u7b279539"><span data-lake-id="u42043133" id="u42043133">意思就是检查父线程中是否有inheritableThreadLocals，如果有，就把他复制到子线程的inheritableThreadLocals中！</span></p>
 </body>
</html>